/*
 * Copyright 2010 Christoph Widulle (christoph.widulle@googlemail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */



package com.android1.amarena2d.engine;

import com.android1.amarena2d.annotations.NotThreadsave;
import com.android1.amarena2d.commons.VoidFunction;
import com.android1.amarena2d.nodes.behavior.LifecyleTick;
import com.android1.amarena2d.commons.collections.FixedSizeStagingList;

@NotThreadsave
public class Scheduler extends EngineObject {

    public static final String LOG_TAG = Scheduler.class.getName();

    private final FixedSizeStagingList<Timer> activeTimer;

    public Scheduler() {

        activeTimer = new FixedSizeStagingList<Timer>(engine.getConfig().get(Config.TIMER_MAX_ACTIVE));

        TickTimer.createPool(engine.getConfig().get(Config.TIMER_LIFECYCLE_POOL_SIZE));
        FunctionTimer.createPool(engine.getConfig().get(Config.TIMER_CALLBACK_POOL_SIZE));
    }


    void tick(float dt) {

        synchronized (activeTimer) {
            activeTimer.applyChanges();
            int s = activeTimer.getCount();
            for (int i = 0; i < s; i++) {
                Timer timer = this.activeTimer.get(i);
                timer.tick(dt);
                if (timer.isFinished()) {
                    this.activeTimer.remove(timer);
                    if (timer.isRecyclable()) {
                        timer.recycle();
                    }
                }
            }
        }
    }

    public TickTimer schedule(LifecyleTick lifecyleTick) {
        TickTimer timer = TickTimer.obtain(lifecyleTick);
        this.schedule(timer);
        return timer;
    }

    public TickTimer schedule(float interval, int repetition, LifecyleTick lifecyleTick) {
        TickTimer timer = TickTimer.obtain(lifecyleTick, interval, repetition);
        this.schedule(timer);
        return timer;
    }

    public TickTimer schedule(float interval, LifecyleTick lifecyleTick) {
        TickTimer timer = TickTimer.obtain(lifecyleTick, interval);
        this.schedule(timer);
        return timer;
    }


    public TickTimer scheduleOnce(float interval, LifecyleTick lifecyleTick) {
        TickTimer timer = TickTimer.obtain(lifecyleTick, interval, 1);
        this.schedule(timer);
        return timer;
    }

    public TickTimer scheduleOnce(LifecyleTick lifecyleTick) {
        TickTimer timer = TickTimer.obtain(lifecyleTick, 0, 1);
        this.schedule(timer);
        return timer;
    }


    public FunctionTimer schedule(VoidFunction function) {
        FunctionTimer timer = FunctionTimer.obtain(function);
        this.schedule(timer);
        return timer;
    }

    public FunctionTimer schedule(float interval, int repetition, VoidFunction function) {
        FunctionTimer timer = FunctionTimer.obtain(function, interval, repetition);
        this.schedule(timer);
        return timer;
    }

    public FunctionTimer schedule(float interval, VoidFunction function) {
        FunctionTimer timer = FunctionTimer.obtain(function, interval);
        this.schedule(timer);
        return timer;
    }


    public FunctionTimer scheduleOnce(float interval, VoidFunction function) {
        FunctionTimer timer = FunctionTimer.obtain(function, interval, 1);
        this.schedule(timer);
        return timer;
    }

    public FunctionTimer scheduleOnce(VoidFunction function) {
        FunctionTimer timer = FunctionTimer.obtain(function, 0, 1);
        this.schedule(timer);
        return timer;
    }


    public void unschedule(Timer t) {
        activeTimer.remove(t);
        if (t.isRecyclable())
            t.recycle();
    }


    public Timer schedule(Timer t) {
        try {
            activeTimer.add(t);
        } catch (IndexOutOfBoundsException e) {
            throw new IndexOutOfBoundsException("Scheduler timer size exhausted.");
        }
        return t;
    }


}
